package springapp.web.managers;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author sad
 */
public abstract class BaseManager<T> {

    @Autowired
    private SessionFactory sessionFactory;

    private static Class getTClassFromClass(Class clazz) {
        Type genericSuperclass = clazz.getGenericSuperclass();
        while (!(genericSuperclass instanceof ParameterizedType)) {
            clazz = clazz.getSuperclass();
            genericSuperclass = clazz.getGenericSuperclass();
        }

        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) genericSuperclass;
            return (Class) pt.getActualTypeArguments()[0];
        }

        throw new IllegalStateException("Wrong parametrized type");
    }

    private static Class getTClass(Object o) {
        Class clazz = o.getClass();
        return getTClassFromClass(clazz);
    }

    protected Session getSession() {
        return sessionFactory.openSession();
    }

    public T findById(long id) {
        return (T) getSession().get(getTClass(this), id);
    }
    
    protected List<T> listAll() {
        return getCriteria().list();
    }

    public void delete(T object) {
        getSession().delete(object);
    }

    public void saveOrUpdate(T object) {
        getSession().saveOrUpdate(object);
    }

    protected Criteria getCriteria() {
        return getSession().createCriteria(getTClass(this));
    }

    @SuppressWarnings("unchecked")
    protected List<T> getElementsByFields(Object... fields) {
        return getCriteriaForFields(fields).list();
    }

    protected Criteria getCriteriaForFields(Object... fields) {
        Criteria criteria = getCriteria();
        for (int i = 0; i < fields.length; i++) {
            String field = fields[i].toString();
            i++;
            Object value = fields[i];
            criteria.add(Restrictions.eq(field, value));
        }
        return criteria;
    }
}
